import Joi, { string } from "joi";

// 自定义一个校验布尔值的方法
const strictBoolean = (value: any) => {
  // 检查值是否是严格的布尔值
  if (typeof value !== "boolean") {
    return `must be a boolean, but got ${typeof value}`;
  }
  return null; // 没有错误时返回 null
};

// 子模式
const desensitizationSchema = Joi.object({
  type: Joi.string().required().allow("").allow(null),
});

// tips 子模式
const tipsLinkSchema = Joi.object({
  url: Joi.string().optional().allow("").allow(null),
  target: Joi.string().optional().allow("").allow(null),
  text: Joi.string().optional().allow("").allow(null),
}).unknown(true);

const tipsSchema = Joi.alternatives().try(
  Joi.string().allow(null).allow(""), // 字符串
  tipsLinkSchema.allow(null).optional() // tipsLinkSchema
);

//定义 optionsSchema 专用的校验模式
const optionsSchema = Joi.array().items(
  Joi.object({
    name: Joi.string().required().description("选项名称").allow("").allow(null),
    value: Joi.string().required().description("选项值").allow("").allow(null),
  }).unknown(true)
);

// 定义 NUMBER_RESTRICTION 专用的校验模式
const numberRestrictionSchema = {
  min: Joi.when("restrictionType", {
    is: "NUMBER_RESTRICTION",
    then: Joi.number().integer().min(0).description("最小值（不包括）"),
  }),
  max: Joi.when("restrictionType", {
    is: "NUMBER_RESTRICTION",
    then: Joi.number().integer().required().description("最大值"),
  }),
  maxInclusive: Joi.when("restrictionType", {
    is: "NUMBER_RESTRICTION",
    then: Joi.boolean()
      .custom(strictBoolean, "严格校验布尔值")
      .required()
      .description("最大值是否包含在内"),
  }),
  minInclusive: Joi.when("restrictionType", {
    is: "NUMBER_RESTRICTION",
    then: Joi.boolean()
      .custom(strictBoolean, "严格校验布尔值")
      .required()
      .description("最小值是否包含在内"),
  }),
  dpAllowed: Joi.when("restrictionType", {
    is: "NUMBER_RESTRICTION",
    then: Joi.number().integer().min(0).description("允许的小数位数"),
  }),
};

//COMMON_RESTRICTION 专用的校验模式
const lengthRestrictionSchema = {
  minLength: Joi.when("restrictionType", {
    is: "COMMON_RESTRICTION",
    then: Joi.number().integer().min(0).description("最小长度"),
    otherwise: Joi.forbidden(),
  }),
  maxLength: Joi.when("restrictionType", {
    is: "COMMON_RESTRICTION",
    then: Joi.number().integer().required().description("最大长度"),
    otherwise: Joi.forbidden(),
  }),
};

// PATTERN_RESTRICTION 专用的校验模式
const patternRestrictionSchema = {
  regex: Joi.when("restrictionType", {
    is: "PATTERN_RESTRICTION",
    then: Joi.string()
      .required()
      .description("正则表达式")
      .allow("")
      .allow(null),
    otherwise: Joi.forbidden(),
  }),
  msg: Joi.when("restrictionType", {
    is: "PATTERN_RESTRICTION",
    then: Joi.string()
      .optional()
      .description("校验失败提示信息")
      .allow("")
      .allow(null),
    otherwise: Joi.forbidden(),
  }),
};

const optionRestrictionSchema = Joi.object({
  optionGlobalKey: Joi.when("restrictionType", {
    is: "OPTION_RESTRICTION",
    then: Joi.string().description("全局选项键"),
    otherwise: Joi.forbidden(),
  }),
  options: Joi.when("restrictionType", {
    is: "OPTION_RESTRICTION",
    then: optionsSchema.required().description("选项集合"), // Assuming optionsSchema is a Joi.object()
    otherwise: Joi.forbidden(),
  }),
}).or("optionGlobalKey", "options");

// 定义 restriction 对象的校验模式
const restrictionSchema = Joi.object({
  restrictionType: Joi.string().required().description("限制类型"),
  ...numberRestrictionSchema,
  ...lengthRestrictionSchema,
  ...patternRestrictionSchema,
  restrictionItems: Joi.array().when("restrictionType", {
    is: "ARRAY_AND_RESTRICTION",
    then: Joi.array()
      .items(Joi.link("..."))
      .optional()
      .description("数组元素的限制模式"),
    otherwise: Joi.forbidden(),
  }),
  optionRestrictionSchema,
  //optionGlobalKey和options是互斥的，只能有一个
}).unknown(true);

const uiInfosSchema = Joi.object({
  tips: tipsSchema.allow(null),
  tipsKey: Joi.string().optional().allow("").allow(null),
  leaf: Joi.boolean().custom(strictBoolean, "严格校验布尔值").optional(),
  uiType: Joi.string().optional().allow("").allow(null),
  list: Joi.boolean().custom(strictBoolean, "严格校验布尔值").optional(),
  placeholder: Joi.alternatives()
    .try(Joi.string().allow("").allow(null), Joi.object())
    .optional(),
  placeholderKey: Joi.string().optional().allow("").allow(null),
  extraProps: Joi.object().pattern(Joi.string(), Joi.any()).optional(), // 处理动态键
  requiredTips: Joi.string().optional().allow("").allow(null),
  requiredTipsKey: Joi.string().optional().allow("").allow(null),
  viewOnly: Joi.boolean().custom(strictBoolean, "严格校验布尔值").optional(),
}).pattern(Joi.string(), Joi.any()); // 处理可能有的其他键

// plugins 校验器
const pluginRestrictionSchema = Joi.object({
  name: Joi.string().allow("SET_STATE").required().allow("").allow(null),
  value: Joi.any().optional(),
  event: Joi.string()
    .allow("onChange", "onBlur", "onFocus", string)
    .optional()
    .allow("")
    .allow(null),
  changes: Joi.array()
    .items(
      Joi.object({
        targetPath: Joi.string().required().allow("").allow(null),
        value: Joi.alternatives()
          .try(Joi.any(), Joi.object().pattern(Joi.string(), Joi.any()))
          .required(),
        props: Joi.object().pattern(Joi.string(), Joi.any()).optional(),
        apiName: Joi.string().optional().allow("").allow(null),
        pluginReverse: Joi.boolean().optional(),
        states: Joi.object({
          value: Joi.any().optional(),
          display: Joi.boolean().optional(),
          editable: Joi.boolean().optional(),
          required: Joi.boolean().optional(),
          visible: Joi.boolean().optional(),
          noMatchedValue: Joi.any().optional(),
          label: Joi.object().pattern(Joi.string(), Joi.any()).optional(),
          props: Joi.object().pattern(Joi.string(), Joi.any()).optional(),
          noReverse: Joi.boolean().optional(),
          dependence: Joi.array()
            .items(
              Joi.object({
                dependencePath: Joi.string().required().allow("").allow(null),
                value: Joi.any().required(),
              }).unknown(true)
            )
            .optional(),
        }).unknown(true),
        dependence: Joi.array()
          .items(
            Joi.object({
              dependencePath: Joi.string().required().allow("").allow(null),
              value: Joi.any().required(),
            })
          )
          .optional(),
      })
    )
    .required(),
}).unknown(true);

// 主模式
export const schemaElementSchema = Joi.object({
  displayName: Joi.string().optional().allow("").allow(null),
  displayNameKey: Joi.string().optional().allow("").allow(null),
  displayNameHelp: Joi.string().optional().allow("").allow(null),
  editable: Joi.boolean().custom(strictBoolean, "严格校验布尔值").optional(),
  elementName: Joi.string().optional().allow("").allow(null),
  // 需要更加完善(加完)
  restriction: restrictionSchema.optional(),
  tips: tipsSchema.optional(),
  tipsKey: Joi.string().optional().allow("").allow(null),
  description: Joi.string().optional().allow("").allow(null),
  descriptionKey: Joi.string().optional().allow("").allow(null),
  required: Joi.boolean().custom(strictBoolean, "严格校验布尔值").optional(),
  elements: Joi.array().items(Joi.link("#schemaElementSchema")).optional(), // 使用 Joi.link 进行递归定义
  desensitization: desensitizationSchema.optional(),
  display: Joi.boolean().custom(strictBoolean, "严格校验布尔值").optional(),
  visible: Joi.boolean().custom(strictBoolean, "严格校验布尔值").optional(),
  uiInfos: uiInfosSchema.optional(),
  defaultValue: Joi.any().optional(),
  requiredMsg: Joi.string().optional().allow("").allow(null),
  // 需要完善（完善ok）
  plugins: Joi.array().items(pluginRestrictionSchema).optional(),
})
  .pattern(Joi.string(), Joi.any())
  .id("schemaElementSchema"); // 添加模式标识符
